#include"MrpcChannel.h"
#include "MrpcLog.h"
#include "rpc_header.pb.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <google/protobuf/descriptor.h>
#include <iostream>
#include <netinet/in.h>
#include <string>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <cerrno>
#include "zookeeperutil.h"
void MrpcChannel::CallMethod(const google::protobuf::MethodDescriptor* method,
                      google::protobuf::RpcController* controller, const google::protobuf::Message* request,
                      google::protobuf::Message* response, google::protobuf::Closure* done)
{
    //需要得到序列化后的字节流
    mrpc::RpcHeader header;
    //rpc_header 包含 service_name method_name, args_len

    // service_name
    const google::protobuf::ServiceDescriptor* service = method->service();
    std::string service_name = service->name();//service_name();
    std::string method_name = method->name();//method_name();
    std::string args;
    uint32_t args_len = args.size();
    if(request->SerializeToString(&args)){
        args_len = args.size();  
    }else{
        controller->SetFailed("serialize args error");
    }

    header.set_args_len(args.size());
    header.set_service_name(service_name);
    header.set_method_name(method_name);
    
    std::string header_str;

    uint32_t header_len = 0;
    if(header.SerializeToString(&header_str)){
        header_len = header_str.size();
    }else{
        // std::cout << "serialize header error"<<std::endl;
        char tmpbuf[512];
        sprintf(tmpbuf,"create socket error: %d",errno);//在末尾添加‘\0’,这是C标准库中字符串处理函数的标准行为。
        controller->SetFailed(tmpbuf);
        return;
    }

    //序列化：确定？？
    std::string send_rpc_str;
    send_rpc_str.insert(0,std::string((char*)(&header_len),4));
    send_rpc_str += header_str;
    send_rpc_str += args;
   
    std::cout<<"send_rpc_str:---------------------"<<std::endl;
    std::cout<<"header_len: "<<header_len<<std::endl;
    std::cout<<"header_str: "<<header_str<<std::endl;
    std::cout<<"service_name: "<<service_name<<std::endl; 
    std::cout<<"method_name: "<<method_name<<std::endl;
    std::cout<<"args: "<<args<<std::endl;
    std::cout<<"send_rpc_str: "<<send_rpc_str<<std::endl;
    std::cout<<"----------------------------------"<<std::endl;
    //使用socket发送rpc请求
    uint32_t client_fd = socket(AF_INET, SOCK_STREAM, 0);//记得使用智能指针生成器来创建socket_fd管理器
    if(-1 == client_fd){
        char tmpbuf[512];
        sprintf(tmpbuf,"create socket error: %d",errno);//在末尾添加‘\0’,这是C标准库中字符串处理函数的标准行为。
        controller->SetFailed(tmpbuf);
        return;
    }

    // std::string ip = MrpcApplication::GetInstance().GetConfig().Load("rpcserverip");//通过配置文件得到ip和port,启动client端进行配置文件读取，单例模式
    // uint32_t port = stoi(MrpcApplication::GetInstance().GetConfig().Load("rpcserverport"));
    // std::cout<<"ip:"<<ip<<" port:"<<port<<std::endl;
    // 从配置文件中获取ip和port，替换为从zookeeper服务注册中心获取的ip和port
    Zkclient zk_client_;
    zk_client_.Start(); //启动Zkclient连接zk，获得Zkclient句柄
    std::string method_path = "/" + service_name + "/" + method_name; //获取方法的路径
    std::string znode_data=zk_client_.GetData(method_path); //获取zookeeper中注册的服务节点数据
    if(znode_data.empty()){
        LOG_ERROR("znode_data is null , %s invalid", method_path.c_str());
    }
    if(znode_data.find(":") == std::string::npos){
        LOG_ERROR("znode_data format error, %s invalid", method_path.c_str());
        controller->SetFailed("znode_data format error");
        close(client_fd);
        return;
    }    
    std::string ip = znode_data.substr(0, znode_data.find(":"));
    uint16_t port = std::stoi(znode_data.substr(znode_data.find(":") + 1));
    std::cout<<"ip:"<<ip<<" port:"<<port<<std::endl;
    
    //创建服务器地址结构体

    struct sockaddr_in server_addr;//创建服务器地址结构体
    server_addr.sin_family = AF_INET;//协议族，
    server_addr.sin_port = htons(port);//端口号，host2net，需要转为大端，
    server_addr.sin_addr.s_addr = inet_addr(ip.c_str());

    //链接rpc服务节点。
    if(-1 == connect(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))){
        char tmpbuf[512];
        sprintf(tmpbuf,"connect error: %d",errno);//在末尾添加‘\0’,这是C标准库中字符串处理函数的标准行为。
        controller->SetFailed(tmpbuf);
        close(client_fd);
        return;
    }
    
    //发送rpc请求
    if(-1 == send(client_fd, send_rpc_str.c_str(), send_rpc_str.size(), 0)){\
        char tmpbuf[512];
        sprintf(tmpbuf,"send error: %d",errno);//在末尾添加‘\0’,这是C标准库中字符串处理函数的标准行为。
        controller->SetFailed(tmpbuf);
        close(client_fd);
        return;
    }

    //接收rpc请求
    char buffer[1024] = {0};  
    size_t recv_size = recv(client_fd,buffer,sizeof(buffer),0);
    if(recv_size == -1){//接受receive
        char tmpbuf[512];
        sprintf(tmpbuf,"recv error: %d",errno);//在末尾添加‘\0’,这是C标准库中字符串处理函数的标准行为。
        controller->SetFailed(tmpbuf);
        close(client_fd);
        return;
    }
    std::string recv_str(buffer,recv_size);
    response->ParseFromString(recv_str);
    //一次调用就可以
    close(client_fd);
    return;
} 
